<?php
namespace app\common\loglic;

use app\common\model\Info;

use think\Validate;

//模型基础方法
class Model
{
    protected $error = '参数错误';
    
    //验证规则
    public $validateRule = [
        //'name'  => 'require',
    ];
    
    //提示信息
    public $validateMsg  =   [
        //'name.require' => '名称必须',    
    ];
    
    /**
     * 将数据添加至数据库
     * @version 1.0.0 首次引入
     * @param string $table 表名
     * @param array $data 待写入数据
     * @return int 返回自增ID或0
     */
    public function dbSave($table='', $data=[])
    {
        if(!$this->validateData($data)){
            return 0;
        }
        return db($table)->strict(false)->insertGetId($data);
    }
    
    /**
     * 添加多条数据（支持replace）
     * @version 1.0.0 首次引入
     * @param string $table 表名
     * @param array $list 数据、二维数组
     * @return int 返回添加成功的条数
     */
    public function dbSaveAll($table='', $list=[])
    {
        return db($table)->insertAll($list, true);
    }
    
    /**
     * 按条件删除数据
     * @version 1.0.0 首次引入
     * @param string $table 表名
     * @param array $where 条件
     * @return int 影响数据的条数，没有删除返回0
     */
    public function dbDelete($table='', $where=[])
    {
        return db($table)->fetchSql(false)->where($where)->delete();
    }
    
    /**
     * 按主键删除数据
     * @version 1.0.0 首次引入
     * @param string $table 表名
     * @param mixed $id 单个ID或多个ID（多个ID为数组格式）
     * @return int 影响数据的条数，没有删除返回0
     */
    public function dbDeleteId($table='',$id=[])
    {
        return db($table)->fetchSql(false)->delete($id);
    }
    
    /**
     * 按条件更新数据
     * @version 1.0.0 首次引入
     * @param string $table 表名
     * @param array $where 条件
     * @param array $data 数据
     * @return int 影响数据的条数，没修改任何数据返回 0
     */
    public function dbUpdate($table='', $where=[], $data=[])
    {
        if(!$this->validateData($data)){
            return 0;
        }
        return db($table)->where($where)->update($data);
    }
    
    /**
     * 按主键ID更新数据
     * @version 1.0.0 首次引入
     * @param string $table 表名
     * @param array $data 数据
     * @return int 影响数据的条数，没修改任何数据返回 0
     */
    public function dbUpdatePk($table='', $data=[])
    {
        return db($table)->update($data);
    }
    
    /**
     * 查询单条数据
     * @version 1.0.0 首次引入
     * @param string $table 表名
     * @param array $params 查询参数
     * @return mixed 不为空时返回obj(null|obj)
     */
    public function dbGet($table='', $args=[])
    {
        //参数过滤
        $args = $this->dbFilter($args);
        //查询实例
        $result = db($table);
        //链式操作
        foreach($args as $key=>$value){
            $result->$key($value);
        }
        //查询结果
        return dcArrayResult($result->find());
    }
    
    /**
     * 查询多条数据
     * @version 1.0.0 首次引入
     * @param string $table 表名
     * @param array $args 查询参数
     * @return aray 二维数组
     */
    public function dbSelect($table='', $args=[])
    {
        //参数过滤
        $args = $this->dbFilter($args);
        //查询实例
        $result = db($table);
        //链式操作
        foreach($args as $key=>$value){
            $result->$key($value);
        }
        //查询结果
        return dcArrayResult($result->select());
    }
    
    /**
     * 分页查询多条数据
     * @version 1.0.0 首次引入
     * @param string $name 资源地址(common/Nav)
     * @param array $params 查询参数
     * @return mixed 不为空时返回obj(null|obj)
     */
    public function dbSelectPage($table='', $args=[], $pageSize=10, $pageNumber=1, $isTotal=false, $query=[]){
        //参数过滤
        $args = $this->dbFilter($args);
        //查询实例
        $result = db($table);
        //链式操作
        foreach($args as $key=>$value){
            $result->$key($value);
        }
        //查询结果
        return $result->paginate($pageSize, $isTotal, [
            'list_rows' => $pageSize,
            'page'      => $pageNumber,
            'query'     => $query,
        ]);
    }
    
    /**
     * 将数据添加至数据库
     * @version 1.0.0 首次引入
     * @param string $name 资源地址(common/Nav)
     * @param array $data 待写入数据(二维数组，第一个为基础数据表)
     * @return int 返回自增ID或0
     */
    public function modelSave($name='', $data=[])
    {
        //实例化模型
        $model = model($name);
        //基础数据表名
        $tableBase = key($data);
        //获取主键
        $pk = model($name)->getPk();
        //关联写入数据
        foreach($data as $table=>$value){
            //删除主键
            unset($value[$pk]);
            //判断数据
            if(!$value){
                continue;
            }
            //基础数据
            if($table == $tableBase){
                $model->data($value, true)->allowField(true)->isUpdate(false)->save();
            }else{
                $relationTable = dcCamelize($table);
                if(dcIsArray($value,true)){
                    $model->$relationTable()->saveAll($value);
                }else{
                    $model->$relationTable()->save($value);
                }
            }
        }
        //返回自增ID
        return $model->$pk;
    }
    
    /**
     * 删除一条数据
     * @version 1.1.0 首次引入
     * @param string $name 资源地址(common/Nav)
     * @param array $where 查询条件
     * @param array $tables 关联表/多个用,分隔/不需要表前缀/如:user_meta
     * @return bool true|false
     */
    public function modelDelete($name='', $where=[], $tables=[])
    {
        //获取主键
        $pk = model($name)->getPk();
        //查询主键值
        if(!$result = model($name)->field($pk)->get($where)){
            return false;
        }
        //return $resul->together($tables)->delete();
        //关联表
        if(is_string($tables)){
            $tables = explode(',',$tables);
        }
        //删除关联数据
        foreach($tables as $key=>$table){
            $table = dcCamelize($table);
            $result->$table()->delete();
        }
        //删除基础数据表
        return $result->delete();
    }
    
    /**
     * 修改一条数据
     * @version 1.0.0 首次引入
     * @param string $name 资源地址(common/Nav)
     * @param array $where 更新条件
     * @param array $data 待写入数据(二维数组，第一个为基础数据表) 
     * @return int 记录数
     */
    public function modelUpdate($name='', $where=[], $data=[])
    {
        //获取主键
        $pk = model($name)->getPk();
        //查询数据
        if(!$result = model($name)->field($pk)->get($where)){
            return 0;
        }
        //基础数据表名
        $tableBase = key($data);
        //关联更新数据
        foreach($data as $table=>$value){
            //判断数据
            if(!$value){
                continue;
            }
            //基础数据表
            if($table == $tableBase){
                $value[$pk] = $result[$pk];
                $resultUpdate = $result->allowField(true)->fetchSql(false)->update($value);
            }else{
                $relationTable = dcCamelize($table);
                //删除关联数据
                $result->$relationTable()->delete();
                //重新添加关联数据
                if(dcIsArray($value,true)){
                    $result->$relationTable()->saveAll($value);
                }else{
                    $result->$relationTable()->save($value);
                }
            }
        }
        //返回修改记录数
        return $resultUpdate;
    }
    
    /**
     * 查询单条数据
     * @version 1.0.0 首次引入
     * @param string $name 模型名
     * @param array $params 查询参数
     * @return mixed 不为空时返回obj(null|obj)
     */
    public function modelGet($name='', $args=[])
    {
        //模型实例
        $result = model($name);
        //缓存设置
        if(is_numeric($args['cache'])){
            $result = $result->cache(true, $args['cache'], 'find_'.$model->getPk());
        }
        //参数过滤
        $args = $this->dbFilter($args);
        //链式操作
        foreach($args as $key=>$value){
            $result = $result->$key($value);
        }
        //查询结果
        return dcArrayResult($result->find());
    }
    
    /**
     * 查询多条数据
     * @version 1.0.0 首次引入
     * @param string $name 模型名
     * @param array $args 查询参数
     * @return aray 二维数组
     */
    public function modelSelect($name='', $args=[])
    {
        //模型实例
        $result = model($name);
        //缓存设置
        if(is_numeric($args['cache'])){
            $result = $result->cache(true, $args['cache'], 'select_'.$model->getPk());
        }
        //参数过滤
        $args = $this->dbFilter($args);
        //链式操作
        foreach($args as $key=>$value){
            $result = $result->$key($value);
        }
        //查询结果
        return dcArrayResult($result->select());
    }
    
    /**
     * 分页查询多条数据
     * @version 1.0.0 首次引入
     * @param string $name 资源地址(common/Nav)
     * @param array $params 查询参数
     * @return mixed 不为空时返回obj(null|obj)
     */
    public function modelSelectPage($name='',$args=[],$pageSize=10,$pageNumber=1,$isTotal=false,$query=['page'=>1])
    {
        //模型实例
        $result = model($name);
        //缓存设置
        if(is_numeric($args['cache'])){
            $result = $result->cache(true, $args['cache'], 'select_'.$model->getPk());
        }
        //参数过滤
        $args = $this->dbFilter($args);
        //链式操作
        foreach($args as $key=>$value){
            $result = $result->$key($value);
        }
        //查询结果
        return $result->paginate($pageSize, $isTotal, [
            'list_rows' => $pageSize,
            'page'      => $pageNumber,
            'query'     => $query,
        ]);
    }
    
    //链式操作过滤
    private function dbFilter($args=[]){
        return dcArrayFilter($args,['where','whereOr','wheretime','table','alias','field','order','limit','page','group','having','join','union','view','distinct','lock','relation','with','bind','comment','force','master','strict','sequence','failException','partition','fetchSql','paginate']);
    }
    
    //返回错误信息
    public function getError()
    {
        return $this->error;
    }
    
    //自动转拼音
    public function getEnglish($english='',$name='')
    {
        if(!$english){
            if(!$name){
                return uniqid();
            }
            return dcPinYin($name,3,false,'');
        }
        return $english;
    }
    
    //独立验证方法
    public function validateData($data=[])
    {
        if(!$this->validateRule){
            return true;
        }
        $validate = Validate::make($this->validateRule, $this->validateMsg);
        if(!$validate->check($data)) {
            $this->error = $validate->getError();
            return false;
        }
        return true;
    }
}